package com.cryptoneedle.center.source.dolphin.api;


import com.cryptoneedle.center.config.helper.ConfigPropertyHelper;
import com.cryptoneedle.center.source.dolphin.config.ClientResult;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

public class WorkflowDefinitionApiClient {

    private final RestTemplate restTemplate;

    public WorkflowDefinitionApiClient(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    private String base(String path) {
        String base = ConfigPropertyHelper.dsUrl();
        return path.startsWith("/") ? base + path : base + "/" + path;
    }

    public ClientResult<JsonNode> createWorkflowDefinition(long projectCode,
                                                           String name,
                                                           String description,
                                                           String globalParams,
                                                           String locations,
                                                           int timeout,
                                                           String taskRelationJson,
                                                           String taskDefinitionJson,
                                                           String otherParamsJson,
                                                           String executionType) {
        String url = base("/projects/" + projectCode + "/workflow-definition");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("name", name);
        if (description != null) form.add("description", description);
        form.add("globalParams", globalParams == null ? "[]" : globalParams);
        if (locations != null) form.add("locations", locations);
        form.add("timeout", String.valueOf(timeout));
        form.add("taskRelationJson", taskRelationJson);
        form.add("taskDefinitionJson", taskDefinitionJson);
        if (otherParamsJson != null) form.add("otherParamsJson", otherParamsJson);
        form.add("executionType", executionType == null ? "PARALLEL" : executionType);
        ResponseEntity<ClientResult> resp = restTemplate.postForEntity(url, new HttpEntity<>(form, headers), ClientResult.class);
        return resp.getBody();
    }

    public ClientResult<JsonNode> batchCopyByCodes(long projectCode, String codes, long targetProjectCode) {
        String url = base("/projects/" + projectCode + "/workflow-definition/batch-copy");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("codes", codes);
        form.add("targetProjectCode", String.valueOf(targetProjectCode));
        return restTemplate.postForObject(url, new HttpEntity<>(form, headers), ClientResult.class);
    }

    public ClientResult<JsonNode> batchMoveByCodes(long projectCode, String codes, long targetProjectCode) {
        String url = base("/projects/" + projectCode + "/workflow-definition/batch-move");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("codes", codes);
        form.add("targetProjectCode", String.valueOf(targetProjectCode));
        return restTemplate.postForObject(url, new HttpEntity<>(form, headers), ClientResult.class);
    }

    public ClientResult<JsonNode> verifyName(long projectCode, String name, Long workflowDefinitionCode) {
        StringBuilder sb = new StringBuilder("/projects/")
                .append(projectCode)
                .append("/workflow-definition/verify-name?name=")
                .append(name);
        if (workflowDefinitionCode != null) {
            sb.append("&workflowDefinitionCode=").append(workflowDefinitionCode);
        }
        return restTemplate.getForObject(base(sb.toString()), ClientResult.class);
    }

    public ClientResult<JsonNode> updateWorkflowDefinition(long projectCode,
                                                           long code,
                                                           String name,
                                                           String description,
                                                           String globalParams,
                                                           String locations,
                                                           int timeout,
                                                           String taskRelationJson,
                                                           String taskDefinitionJson,
                                                           String executionType,
                                                           String releaseState) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("name", name);
        if (description != null) form.add("description", description);
        form.add("globalParams", globalParams == null ? "[]" : globalParams);
        if (locations != null) form.add("locations", locations);
        form.add("timeout", String.valueOf(timeout));
        form.add("taskRelationJson", taskRelationJson);
        form.add("taskDefinitionJson", taskDefinitionJson);
        form.add("executionType", executionType == null ? "PARALLEL" : executionType);
        if (releaseState != null) form.add("releaseState", releaseState);
        ResponseEntity<ClientResult> resp = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(form, headers), ClientResult.class);
        return resp.getBody();
    }

    public ClientResult<JsonNode> queryWorkflowDefinitionVersions(long projectCode, long code, int pageNo, int pageSize) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code + "/versions?pageNo=" + pageNo + "&pageSize=" + pageSize);
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> switchWorkflowDefinitionVersion(long projectCode, long code, int version) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code + "/versions/" + version);
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> deleteWorkflowDefinitionVersion(long projectCode, long code, int version) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code + "/versions/" + version);
        ResponseEntity<ClientResult> resp = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, ClientResult.class);
        return resp.getBody();
    }

    public ClientResult<JsonNode> releaseWorkflowDefinition(long projectCode, long code, String releaseState) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code + "/release");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("releaseState", releaseState);
        return restTemplate.postForObject(url, new HttpEntity<>(form, headers), ClientResult.class);
    }

    public ClientResult<JsonNode> queryWorkflowDefinitionByCode(long projectCode, long code) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code);
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> queryWorkflowDefinitionByName(long projectCode, String name) {
        String url = base("/projects/" + projectCode + "/workflow-definition/query-by-name?name=" + name);
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> queryWorkflowDefinitionList(long projectCode) {
        String url = base("/projects/" + projectCode + "/workflow-definition/list");
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> queryWorkflowDefinitionSimpleList(long projectCode) {
        String url = base("/projects/" + projectCode + "/workflow-definition/simple-list");
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> queryWorkflowDefinitionListPaging(long projectCode,
                                                                    String searchVal,
                                                                    String otherParamsJson,
                                                                    Integer userId,
                                                                    Integer pageNo,
                                                                    Integer pageSize) {
        StringBuilder sb = new StringBuilder("/projects/")
                .append(projectCode)
                .append("/workflow-definition?pageNo=")
                .append(pageNo)
                .append("&pageSize=")
                .append(pageSize);
        if (searchVal != null) sb.append("&searchVal=").append(searchVal);
        if (otherParamsJson != null) sb.append("&otherParamsJson=").append(otherParamsJson);
        if (userId != null) sb.append("&userId=").append(userId);
        return restTemplate.getForObject(base(sb.toString()), ClientResult.class);
    }

    public ClientResult<JsonNode> viewTree(long projectCode, long code, int limit) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code + "/view-tree?limit=" + limit);
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> getTasksByDefinitionCode(long projectCode, long code) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code + "/tasks");
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> getTaskListByDefinitionCodes(long projectCode, String codes) {
        String url = base("/projects/" + projectCode + "/workflow-definition/batch-query-tasks?codes=" + codes);
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> getWorkflowListByProjectCode(long projectCode) {
        String url = base("/projects/" + projectCode + "/workflow-definition/query-workflow-definition-list");
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> getTaskListByWorkflowDefinitionCode(long projectCode, long workflowDefinitionCode) {
        String url = base("/projects/" + projectCode + "/workflow-definition/query-task-definition-list?workflowDefinitionCode=" + workflowDefinitionCode);
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> deleteByWorkflowDefinitionCode(long projectCode, long code) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code);
        ResponseEntity<ClientResult> resp = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, ClientResult.class);
        return resp.getBody();
    }

    public ClientResult<JsonNode> batchDeleteByCodes(long projectCode, String codes) {
        String url = base("/projects/" + projectCode + "/workflow-definition/batch-delete");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("codes", codes);
        return restTemplate.postForObject(url, new HttpEntity<>(form, headers), ClientResult.class);
    }

    public ResponseEntity<byte[]> batchExportByCodes(long projectCode, String codes) {
        String url = base("/projects/" + projectCode + "/workflow-definition/batch-export");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("codes", codes);
        return restTemplate.postForEntity(url, new HttpEntity<>(form, headers), byte[].class);
    }

    public ClientResult<JsonNode> queryAllByProjectCode(long projectCode) {
        String url = base("/projects/" + projectCode + "/workflow-definition/all");
        return restTemplate.getForObject(url, ClientResult.class);
    }

    public ClientResult<JsonNode> importWorkflowDefinition(long projectCode, Resource file) {
        String url = base("/projects/" + projectCode + "/workflow-definition/import");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", file);
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
        ResponseEntity<ClientResult> resp = restTemplate.postForEntity(url, requestEntity, ClientResult.class);
        return resp.getBody();
    }

    public ClientResult<JsonNode> viewVariables(long projectCode, long code) {
        String url = base("/projects/" + projectCode + "/workflow-definition/" + code + "/view-variables");
        return restTemplate.getForObject(url, ClientResult.class);
    }
}